package cn.wolfcode.business.service.impl;

import cn.wolfcode.business.domain.BusBpmnInfo;
import cn.wolfcode.business.mapper.BusBpmnInfoMapper;
import cn.wolfcode.business.service.IBusBpmnInfoService;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * 流程定义明细Service业务层处理
 * 
 * @author wolfcode
 * @date 2025-05-08
 */
@Service
public class BusBpmnInfoServiceImpl implements IBusBpmnInfoService 
{
    @Autowired
    private BusBpmnInfoMapper busBpmnInfoMapper;
    @Autowired
    private RepositoryService repositoryService;

    /**
     * 查询流程定义明细
     * 
     * @param id 流程定义明细主键
     * @return 流程定义明细
     */
    @Override
    public BusBpmnInfo selectBusBpmnInfoById(Long id)
    {
        return busBpmnInfoMapper.selectBusBpmnInfoById(id);
    }

    /**
     * 查询流程定义明细列表
     * 
     * @param busBpmnInfo 流程定义明细
     * @return 流程定义明细
     */
    @Override
    public List<BusBpmnInfo> selectBusBpmnInfoList(BusBpmnInfo busBpmnInfo)
    {
        return busBpmnInfoMapper.selectBusBpmnInfoList(busBpmnInfo);
    }

    /**
     * 新增流程定义明细
     * 
     * @param busBpmnInfo 流程定义明细
     * @return 结果
     */
    @Override
    public int insertBusBpmnInfo(BusBpmnInfo busBpmnInfo)
    {
        return busBpmnInfoMapper.insertBusBpmnInfo(busBpmnInfo);
    }

    /**
     * 修改流程定义明细
     * 
     * @param busBpmnInfo 流程定义明细
     * @return 结果
     */
    @Override
    public int updateBusBpmnInfo(BusBpmnInfo busBpmnInfo)
    {
        return busBpmnInfoMapper.updateBusBpmnInfo(busBpmnInfo);
    }

    /**
     * 批量删除流程定义明细
     * 
     * @param ids 需要删除的流程定义明细主键
     * @return 结果
     */
    @Override
    public int deleteBusBpmnInfoByIds(Long[] ids)
    {
        return busBpmnInfoMapper.deleteBusBpmnInfoByIds(ids);
    }

    /**
     * 删除流程定义明细信息
     * 
     * @param id 流程定义明细主键
     * @return 结果
     */
    @Override
    public int deleteBusBpmnInfoById(Long id)
    {
        return busBpmnInfoMapper.deleteBusBpmnInfoById(id);
    }

    /**
     * 文件部署（上传）
     */
    @Override
    @Transactional
    public int deploy(MultipartFile file, String bpmnLabel, Integer bpmnType, String info) throws Exception {
        // 参数安全验证
        if(file == null || bpmnLabel == null || bpmnType == null || info == null){
            throw new RuntimeException("非法参数");
        }
        // 文件类型验证 必须是 bpmn || xml 结尾
        // 安全考虑，我们还是从文件中获取文件的名称
        String originalFilename = file.getOriginalFilename();
        // 通过 common.io 中的工具类来获取文件后缀名
        String extension = FilenameUtils.getExtension(originalFilename);
        if(!("xml".equalsIgnoreCase(extension) || "bpmn".equalsIgnoreCase(extension))){
            throw new RuntimeException("上传文件格式必须以 xml 或 bpmn 结尾");
        }
        // 完成 Activiti7 中的部署操作
        Deployment deploy = repositoryService.createDeployment()
                .addInputStream(originalFilename, file.getInputStream())
                .deploy();
        // 通过部署对象获取部署时间
        Date deploymentTime = deploy.getDeploymentTime();
        // 通过部署对象 id 获取流程定义对象
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploy.getId())
                .singleResult();
        // 向 BpmnInfo 表中插入数据
        BusBpmnInfo bpmnInfo = new BusBpmnInfo();
        bpmnInfo.setBpmnLabel(originalFilename);
        bpmnInfo.setBpmnType(bpmnType);
        bpmnInfo.setProcessDefinitionKey(processDefinition.getKey());
        bpmnInfo.setDeployTime(deploymentTime);
        bpmnInfo.setVersion(processDefinition.getVersion());
        bpmnInfo.setInfo(info);
        return busBpmnInfoMapper.insertBusBpmnInfo(bpmnInfo);
    }

    /**
     * XML 文件查看
     * @param id
     * @param type
     * @return
     */
    @Override
    @Transactional
    public InputStream readResource(Long id, String type) {
        // 验证数据合法性
        if (id == null || type == null) {
            throw new RuntimeException("非法参数");
        }
        // 通过 id 获取 BpmnInfo 对象
        BusBpmnInfo busBpmnInfo = this.selectBusBpmnInfoById(id);
        if(busBpmnInfo == null){
            throw new RuntimeException("非法参数");
        }
        // 通过 BpmnInfo 对象获取流程定义的 Key 和 version
        String processDefinitionKey = busBpmnInfo.getProcessDefinitionKey();
        Integer version = busBpmnInfo.getVersion();
        // 获取到流程定义对象
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(processDefinitionKey)
                .processDefinitionVersion(version)
                .singleResult();
        // 判断类型
        if("xml".equalsIgnoreCase(type)){
            // 查看 xml 文件
            String xmlName = processDefinition.getResourceName();
            // 获取部署 ID
            String deploymentId = processDefinition.getDeploymentId();
            // 获取输入流
            InputStream xmlStream = repositoryService.getResourceAsStream(deploymentId, xmlName);
            return xmlStream;
        } else if("png".equalsIgnoreCase(type)){
            // 查看 png 文件
            // 生成流程图插件，他可以根据我们的文件绘制出流程图。
            DefaultProcessDiagramGenerator processDiagramGenerator = new DefaultProcessDiagramGenerator();
            // BpmnModel 对象
            BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
            /**
             * 第一个参数：模型对象（当前流程都有那些节点，哪些连线，哪些坐标 等等...）
             * 第二个参数：需要高亮的节点。
             * 第三个参数：需要高亮的连线。
             * 第 4 5 6 个参数：生成图后展示的字体。
             */
            InputStream inputStream = processDiagramGenerator.generateDiagram(bpmnModel,
                    Collections.emptyList(),
                    Collections.emptyList(),
                    "宋体",
                    "宋体",
                    "宋体");
            return inputStream;
        } else {
            throw new RuntimeException("非法参数");
        }
    }

    /**
     * 删除流程定义明细
     */
    @Override
    @Transactional
    public int cancel(Long id) {
        // 参数合法性验证
        if(id == null){
            throw new RuntimeException("非法参数");
        }
        BusBpmnInfo busBpmnInfo = this.selectBusBpmnInfoById(id);
        if(busBpmnInfo == null){
            throw new RuntimeException("非法参数");
        }
        // 获取流程定义对象
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(busBpmnInfo.getProcessDefinitionKey())
                .processDefinitionVersion(busBpmnInfo.getVersion())
                .singleResult();
        // 获取部署 ID
        String deploymentId = processDefinition.getDeploymentId();
        // 删除流程定义
        repositoryService.deleteDeployment(deploymentId,true);
        // 删除 BpmnInfo 表中的记录。
        return busBpmnInfoMapper.deleteBusBpmnInfoById(id);
    }

    /**
     * 根据服务类型查询流程定义明细
     * @param type
     * @return
     */
    @Override
    public BusBpmnInfo selectByTypeId(Integer type) {
        return busBpmnInfoMapper.selectByTypeId(type);
    }
}
